import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { Component, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
import { LoadingService } from '../core/services/loading.service';
import { LvLoadingSize } from '../core/types';
import { ButtonModule } from '../button/button.module';
import { LoadingModule } from './loading.module';

@Component({
  template: `
    <lv-loading [lvSize]="lvSize" [lvLoading]="lvLoading" [lvMask]="lvMask" [lvLoadingText]="lvLoadingText"></lv-loading>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
class TestLoadingComponent {
  @Input() lvLoading = true;
  @Input() lvMask = false;
  @Input() lvLoadingText = 'loading';
  @Input() lvSize: LvLoadingSize | number = 'default';

  constructor(private loadingService: LoadingService) {}

  open(text?: string, size?: LvLoadingSize | number): void {
    this.loadingService.show({ text, size });
  }

  close(): void {
    this.loadingService.hide();
  }
}

describe('LoadingComponent', () => {
  beforeEach(waitForAsync(() => {
    TestBed.configureTestingModule({
      imports: [LoadingModule, ButtonModule],
      declarations: [TestLoadingComponent],
      teardown: { destroyAfterEach: true },
    }).compileComponents;
  }));

  describe('render', () => {
    let component: TestLoadingComponent;
    let fixture: ComponentFixture<TestLoadingComponent>;
    let cdr: ChangeDetectorRef;

    const renderComponent = (param?) => {
      for (const [key, value] of Object.entries(param)) {
        component[key] = value;
      }
      cdr.detectChanges();
      expect(fixture).toMatchSnapshot();
    };

    beforeEach(() => {
      fixture = TestBed.createComponent(TestLoadingComponent);
      component = fixture.componentInstance;
      cdr = fixture.debugElement.injector.get(ChangeDetectorRef);
    });

    it('with default', () => {
      renderComponent({});
    });

    it('with lvLoadingText', () => {
      renderComponent({ lvLoadingText: '加载中...' });
    });

    it('with lvMask', () => {
      renderComponent({ lvMask: true });
    });

    it('with lvSize', () => {
      renderComponent({ lvSize: 'mini' });
      renderComponent({ lvSize: 'small' });
      renderComponent({ lvSize: 'medium' });
      renderComponent({ lvSize: 12 });
    });
  });

  describe('global render', () => {
    let component: TestLoadingComponent;
    let fixture: ComponentFixture<TestLoadingComponent>;

    beforeEach(() => {
      fixture = TestBed.createComponent(TestLoadingComponent);
      component = fixture.componentInstance;
    });

    afterEach(() => {
      document.body.innerHTML = '';
    });

    it('with default', () => {
      component.open();
      fixture.detectChanges();
      expect(document.activeElement).toMatchSnapshot();
    });

    it('with text', () => {
      component.open('加载中');
      fixture.detectChanges();
      expect(document.activeElement).toMatchSnapshot();
    });

    it('with size', () => {
      component.open('加载中', 'medium');
      fixture.detectChanges();
      expect(document.activeElement).toMatchSnapshot();
    });
  });

  describe('works', () => {
    let component: TestLoadingComponent;
    let fixture: ComponentFixture<TestLoadingComponent>;
    let cdr: ChangeDetectorRef;

    const getContainer = () => fixture.nativeElement.querySelector('.lv-loading-container');
    const getGlobalContainer = () => document.querySelector('.lv-loading-gloabl-container');

    beforeEach(() => {
      fixture = TestBed.createComponent(TestLoadingComponent);
      component = fixture.componentInstance;
      cdr = fixture.debugElement.injector.get(ChangeDetectorRef);
    });

    it('with component', () => {
      fixture.detectChanges();
      expect(getContainer()).toBeTruthy();

      component.lvLoading = false;
      cdr.detectChanges();
      expect(getContainer()).toBeFalsy();
    });

    it('with service', () => {
      component.open();
      fixture.detectChanges();
      expect(getGlobalContainer()).toBeTruthy();

      component.close();
      cdr.detectChanges();
      expect(getGlobalContainer()).toBeNull();
    });
  });
});
